﻿var qq = qq || {},
    qq = function (e)
    {
        "use strict";
        return {
            hide: function ()
            {
                return e.style.display = "none",
                this;
            },
            attach: function (t, n)
            {
                return e.addEventListener ? e.addEventListener(t, n, !1) : e.attachEvent && e.attachEvent("on" + t, n),
                function ()
                {
                    qq(e).detach(t, n);
                };
            },
            detach: function (t, n)
            {
                return e.removeEventListener ? e.removeEventListener(t, n, !1) : e.attachEvent && e.detachEvent("on" + t, n),
                this;
            },
            contains: function (t)
            {
                return e == t ? !0 : e.contains ? e.contains(t) : !!(8 & t.compareDocumentPosition(e));
            },
            insertBefore: function (t)
            {
                return t.parentNode.insertBefore(e, t),
                this;
            },
            remove: function ()
            {
                return e.parentNode.removeChild(e),
                this;
            },
            css: function (t)
            {
                return null != t.opacity && "string" != typeof e.style.opacity && "undefined" != typeof e.filters && (t.filter = "alpha(opacity=" + Math.round(100 * t.opacity) + ")"),
                qq.extend(e.style, t),
                this;
            },
            hasClass: function (t)
            {
                var n = RegExp("(^| )" + t + "( |$)");
                return n.test(e.className);
            },
            addClass: function (t)
            {
                return qq(e).hasClass(t) || (e.className += " " + t),
                this;
            },
            removeClass: function (t)
            {
                var n = RegExp("(^| )" + t + "( |$)");
                return e.className = e.className.replace(n, " ").replace(/^\s+|\s+$/g, ""),
                this;
            },
            getByClass: function (t)
            {
                if (e.querySelectorAll)
                {
                    return e.querySelectorAll("." + t);
                }
                for (var n = [], i = e.getElementsByTagName("*"), o = i.length, s = 0; s < o; s++)
                {
                    qq(i[s]).hasClass(t) && n.push(i[s]);
                }
                return n;
            },
            children: function ()
            {
                for (var t = [], n = e.firstChild; n;)
                {
                    1 == n.nodeType && t.push(n),
                    n = n.nextSibling;
                }
                return t;
            },
            setText: function (t)
            {
                return e.innerText = t,
                e.textContent = t,
                this;
            },
            clearText: function ()
            {
                return qq(e).setText("");
            }
        };
    };
qq.log = function (e, t)
{
    window.console && (t && "info" !== t ? window.console[t] ? window.console[t](e) : window.console.log("<" + t + "> " + e) : window.console.log(e));
},
qq.isObject = function (e)
{
    "use strict";
    return null !== e && e && "object" === typeof e && e.constructor === Object;
},
qq.extend = function (e, t, n)
{
    "use strict";
    var i;
    for (i in t)
    {
        t.hasOwnProperty(i) && (n && qq.isObject(t[i]) ? (void 0 === e[i] && (e[i] = {}), qq.extend(e[i], t[i], !0)) : e[i] = t[i]);
    }
},
qq.indexOf = function (e, t, n)
{
    if (e.indexOf)
    {
        return e.indexOf(t, n);
    }
    n = n || 0;
    var i = e.length;
    for (n < 0 && (n += i) ; n < i; n++)
    {
        if (n in e && e[n] === t)
        {
            return n;
        }
    }
    return -1;
},
qq.getUniqueId = function ()
{
    var e = 0;
    return function ()
    {
        return e++;
    };
}(),
qq.ie = function ()
{
    return -1 != navigator.userAgent.indexOf("MSIE");
},
qq.ie10 = function ()
{
    return -1 != navigator.userAgent.indexOf("MSIE 10");
},
qq.safari = function ()
{
    return void 0 != navigator.vendor && -1 != navigator.vendor.indexOf("Apple");
},
qq.chrome = function ()
{
    return void 0 != navigator.vendor && -1 != navigator.vendor.indexOf("Google");
},
qq.firefox = function ()
{
    return -1 != navigator.userAgent.indexOf("Mozilla") && void 0 != navigator.vendor && "" == navigator.vendor;
},
qq.windows = function ()
{
    return "Win32" == navigator.platform;
},
qq.preventDefault = function (e)
{
    e.preventDefault ? e.preventDefault() : e.returnValue = !1;
},
qq.toElement = function ()
{
    var e = document.createElement("div");
    return function (t)
    {
        e.innerHTML = t;
        var n = e.firstChild;
        return e.removeChild(n),
        n;
    };
}(),
qq.obj2url = function (e, t, n)
{
    var i = [],
        o = "&",
        s = function (e, n)
        {
            var o = t ? /\[\]$/.test(t) ? t : t + "[" + n + "]" : n;
            "undefined" != o && "undefined" != n && i.push("object" === typeof e ? qq.obj2url(e, o, !0) : "[object Function]" === Object.prototype.toString.call(e) ? encodeURIComponent(o) + "=" + encodeURIComponent(e()) : encodeURIComponent(o) + "=" + encodeURIComponent(e));
        };
    if (!n && t)
    {
        o = /\?/.test(t) ? /\?$/.test(t) ? "" : "&" : "?",
        i.push(t),
        i.push(qq.obj2url(e));
    }
    else if ("[object Array]" === Object.prototype.toString.call(e) && "undefined" != typeof e)
    {
        for (var r = 0,
            a = e.length; r < a; ++r)
        {
            s(e[r], r);
        }
    }
    else if ("undefined" != typeof e && null !== e && "object" === typeof e)
    {
        for (var r in e)
        {
            s(e[r], r);
        }
    }
    else
    {
        i.push(encodeURIComponent(t) + "=" + encodeURIComponent(e));
    }
    return t ? i.join(o) : i.join(o).replace(/^&/, "").replace(/%20/g, "+");
},
qq.DisposeSupport = {
    _disposers: [],
    dispose: function ()
    {
        for (var e; e = this._disposers.shift() ;)
        {
            e();
        }
    },
    addDisposer: function (e)
    {
        this._disposers.push(e);
    },
    _attach: function ()
    {
        this.addDisposer(qq(arguments[0]).attach.apply(this, Array.prototype.slice.call(arguments, 1)));
    }
},
qq.UploadButton = function (e)
{
    this._options = {
        element: null,
        multiple: !1,
        acceptFiles: null,
        name: "file",
        onChange: function ()
        {
        },
        hoverClass: "qq-upload-button-hover",
        focusClass: "qq-upload-button-focus"
    },
    qq.extend(this._options, e),
    qq.extend(this, qq.DisposeSupport),
    this._element = this._options.element,
    qq(this._element).css({
        position: "relative",
        overflow: "hidden",
        direction: "ltr"
    }),
    this._input = this._createInput();
},
qq.UploadButton.prototype = {
    getInput: function ()
    {
        return this._input;
    },
    reset: function ()
    {
        this._input.parentNode && qq(this._input).remove(),
        qq(this._element).removeClass(this._options.focusClass),
        this._input = this._createInput();
    },
    _createInput: function ()
    {
        var e = document.createElement("input");
        this._options.multiple && e.setAttribute("multiple", "multiple"),
        this._options.acceptFiles && e.setAttribute("accept", this._options.acceptFiles),
        e.setAttribute("type", "file"),
        e.setAttribute("name", this._options.name),
        qq(e).css({
            position: "absolute",
            right: 0,
            top: 0,
            fontFamily: "Arial",
            fontSize: "118px",
            margin: 0,
            padding: 0,
            cursor: "pointer",
            opacity: 0
        }),
        this._element.appendChild(e);
        var t = this;
        return this._attach(e, "change",
            function ()
            {
                t._options.onChange(e);
            }),
        this._attach(e, "mouseover",
            function ()
            {
                qq(t._element).addClass(t._options.hoverClass);
            }),
        this._attach(e, "mouseout",
            function ()
            {
                qq(t._element).removeClass(t._options.hoverClass);
            }),
        this._attach(e, "focus",
            function ()
            {
                qq(t._element).addClass(t._options.focusClass);
            }),
        this._attach(e, "blur",
            function ()
            {
                qq(t._element).removeClass(t._options.focusClass);
            }),
        window.attachEvent && e.setAttribute("tabIndex", "-1"),
        e;
    }
},
qq.FineUploaderBasic = function (e)
{
    this._options = {
        debug: !1,
        button: null,
        multiple: !0,
        maxConnections: 3,
        disableCancelForFormUploads: !1,
        autoUpload: !0,
        request: {
            endpoint: "/server/upload",
            params: {},
            customHeaders: {},
            forceMultipart: !1,
            inputName: "qqfile"
        },
        validation: {
            allowedExtensions: [],
            sizeLimit: 0,
            minSizeLimit: 0,
            stopOnFirstInvalidFile: !0
        },
        callbacks: {
            onSubmit: function ()
            {
            },
            onComplete: function ()
            {
            },
            onCancel: function ()
            {
            },
            onUpload: function ()
            {
            },
            onProgress: function ()
            {
            },
            onError: function ()
            {
            },
            onAutoRetry: function ()
            {
            },
            onManualRetry: function ()
            {
            },
            onValidate: function ()
            {
            }
        },
        messages: {
            typeError: "{file} has an invalid extension. Valid extension(s): {extensions}.",
            sizeError: "{file} is too large, maximum file size is {sizeLimit}.",
            minSizeError: "{file} is too small, minimum file size is {minSizeLimit}.",
            emptyError: "{file} is empty, please select files again without it.",
            noFilesError: "No files to upload.",
            onLeave: "The files are being uploaded, if you leave now the upload will be cancelled."
        },
        retry: {
            enableAuto: !1,
            maxAutoAttempts: 3,
            autoAttemptDelay: 5,
            preventRetryResponseProperty: "preventRetry"
        }
    },
    qq.extend(this._options, e, !0),
    this._wrapCallbacks(),
    qq.extend(this, qq.DisposeSupport),
    this._filesInProgress = 0,
    this._storedFileIds = [],
    this._autoRetries = [],
    this._retryTimeouts = [],
    this._preventRetries = [],
    this._handler = this._createUploadHandler(),
    this._options.button && (this._button = this._createUploadButton(this._options.button)),
    this._preventLeaveInProgress();
},
qq.FineUploaderBasic.prototype = {
    log: function (e, t)
    {
        !this._options.debug || t && "info" !== t ? t && "info" !== t && qq.log("[FineUploader] " + e, t) : qq.log("[FineUploader] " + e);
    },
    setParams: function (e)
    {
        this._options.request.params = e;
    },
    getInProgress: function ()
    {
        return this._filesInProgress;
    },
    uploadStoredFiles: function ()
    {
        "use strict";
        for (; this._storedFileIds.length;)
        {
            this._filesInProgress++,
            this._handler.upload(this._storedFileIds.shift(), this._options.request.params);
        }
    },
    clearStoredFiles: function ()
    {
        this._storedFileIds = [];
    },
    retry: function (e)
    {
        return this._onBeforeManualRetry(e) ? (this._handler.retry(e), !0) : !1;
    },
    cancel: function (e)
    {
        this._handler.cancel(e);
    },
    reset: function ()
    {
        this.log("Resetting uploader..."),
        this._handler.reset(),
        this._filesInProgress = 0,
        this._storedFileIds = [],
        this._autoRetries = [],
        this._retryTimeouts = [],
        this._preventRetries = [],
        this._button.reset();
    },
    _createUploadButton: function (e)
    {
        var t = this,
            n = new qq.UploadButton({
                element: e,
                multiple: this._options.multiple && qq.UploadHandlerXhr.isSupported(),
                acceptFiles: this._options.validation.acceptFiles,
                onChange: function (e)
                {
                    t._onInputChange(e);
                }
            });
        return this.addDisposer(function ()
        {
            n.dispose();
        }),
        n;
    },
    _createUploadHandler: function ()
    {
        var e, t = this;
        e = qq.UploadHandlerXhr.isSupported() ? "UploadHandlerXhr" : "UploadHandlerForm";
        var n = new qq[e]({
            debug: this._options.debug,
            endpoint: this._options.request.endpoint,
            forceMultipart: this._options.request.forceMultipart,
            maxConnections: this._options.maxConnections,
            customHeaders: this._options.request.customHeaders,
            inputName: this._options.request.inputName,
            demoMode: this._options.demoMode,
            log: this.log,
            onProgress: function (e, n, i, o)
            {
                t._onProgress(e, n, i, o),
                t._options.callbacks.onProgress(e, n, i, o);
            },
            onComplete: function (e, n, i, o)
            {
                t._onComplete(e, n, i, o),
                t._options.callbacks.onComplete(e, n, i);
            },
            onCancel: function (e, n)
            {
                t._onCancel(e, n),
                t._options.callbacks.onCancel(e, n);
            },
            onUpload: function (e, n, i)
            {
                t._onUpload(e, n, i),
                t._options.callbacks.onUpload(e, n, i);
            },
            onAutoRetry: function (e, n, i, o)
            {
                return t._preventRetries[e] = i[t._options.retry.preventRetryResponseProperty],
                t._shouldAutoRetry(e, n, i) ? (t._maybeParseAndSendUploadError(e, n, i, o), t._options.callbacks.onAutoRetry(e, n, t._autoRetries[e] + 1), t._onBeforeAutoRetry(e, n), t._retryTimeouts[e] = setTimeout(function ()
                {
                    t._onAutoRetry(e, n, i);
                },
                    1e3 * t._options.retry.autoAttemptDelay), !0) : !1;
            }
        });
        return n;
    },
    _preventLeaveInProgress: function ()
    {
        var e = this;
        this._attach(window, "beforeunload",
            function (t)
            {
                if (e._filesInProgress)
                {
                    var t = t || window.event;
                    return t.returnValue = e._options.messages.onLeave,
                    e._options.messages.onLeave;
                }
            });
    },
    _onSubmit: function ()
    {
        this._options.autoUpload && this._filesInProgress++;
    },
    _onProgress: function ()
    {
    },
    _onComplete: function (e, t, n, i)
    {
        this._filesInProgress--,
        this._maybeParseAndSendUploadError(e, t, n, i);
    },
    _onCancel: function (e)
    {
        clearTimeout(this._retryTimeouts[e]);
        var t = qq.indexOf(this._storedFileIds, e);
        this._options.autoUpload || t < 0 ? this._filesInProgress-- : this._options.autoUpload || this._storedFileIds.splice(t, 1);
    },
    _onUpload: function ()
    {
    },
    _onInputChange: function (e)
    {
        this._handler instanceof qq.UploadHandlerXhr ? this._uploadFileList(e.files) : this._validateFile(e) && this._uploadFile(e),
        this._button.reset();
    },
    _onBeforeAutoRetry: function (e, t)
    {
        this.log("Waiting " + this._options.retry.autoAttemptDelay + " seconds before retrying " + t + "...");
    },
    _onAutoRetry: function (e, t)
    {
        this.log("Retrying " + t + "..."),
        this._autoRetries[e]++,
        this._handler.retry(e);
    },
    _shouldAutoRetry: function (e)
    {
        return !this._preventRetries[e] && this._options.retry.enableAuto ? (void 0 === this._autoRetries[e] && (this._autoRetries[e] = 0), this._autoRetries[e] < this._options.retry.maxAutoAttempts) : !1;
    },
    _onBeforeManualRetry: function (e)
    {
        if (this._preventRetries[e])
        {
            return this.log("Retries are forbidden for id " + e, "warn"),
            !1;
        }
        if (this._handler.isValid(e))
        {
            var t = this._handler.getName(e);
            return this._options.callbacks.onManualRetry(e, t) === !1 ? !1 : (this.log("Retrying upload for '" + t + "' (id: " + e + ")..."), this._filesInProgress++, !0);
        }
        return this.log("'" + e + "' is not a valid file ID", "error"),
        !1;
    },
    _maybeParseAndSendUploadError: function (e, t, n, i)
    {
        if (!n.success)
        {
            if (i && 200 !== i.status && !n.error)
            {
                this._options.callbacks.onError(e, t, "XHR returned response code " + i.status);
            }
            else
            {
                var o = n.error ? n.error : "Upload failure reason unknown";
                this._options.callbacks.onError(e, t, o);
            }
        }
    },
    _uploadFileList: function (e)
    {
        var t, n, i;
        if (t = this._getValidationDescriptors(e), t.length > 1 && (i = this._options.callbacks.onValidate(t) === !1), !i)
        {
            if (e.length > 0)
            {
                for (n = 0; n < e.length; n++)
                {
                    if (this._validateFile(e[n]))
                    {
                        this._uploadFile(e[n]);
                    }
                    else if (this._options.validation.stopOnFirstInvalidFile)
                    {
                        return;
                    }
                }
            }
            else
            {
                this._error("noFilesError", "");
            }
        }
    },
    _uploadFile: function (e)
    {
        var t = this._handler.add(e),
            n = this._handler.getName(t);
        this._options.callbacks.onSubmit(t, n) !== !1 && (this._onSubmit(t, n), this._options.autoUpload ? this._handler.upload(t, this._options.request.params) : this._storeFileForLater(t));
    },
    _storeFileForLater: function (e)
    {
        this._storedFileIds.push(e);
    },
    _validateFile: function (e)
    {
        var t, n, i;
        return t = this._getValidationDescriptor(e),
        n = t.name,
        i = t.size,
        this._options.callbacks.onValidate([t]) === !1 ? !1 : this._isAllowedExtension(n) ? 0 === i ? (this._error("emptyError", n), !1) : i && this._options.validation.sizeLimit && i > this._options.validation.sizeLimit ? (this._error("sizeError", n), !1) : i && i < this._options.validation.minSizeLimit ? (this._error("minSizeError", n), !1) : !0 : (this._error("typeError", n), !1);
    },
    _error: function (e, t)
    {
        function n(e, t)
        {
            i = i.replace(e, t);
        }
        var i = this._options.messages[e],
            o = this._options.validation.allowedExtensions.join(", ");
        return n("{file}", this._formatFileName(t)),
        n("{extensions}", o),
        n("{sizeLimit}", this._formatSize(this._options.validation.sizeLimit)),
        n("{minSizeLimit}", this._formatSize(this._options.validation.minSizeLimit)),
        this._options.callbacks.onError(null, t, i),
        i;
    },
    _formatFileName: function (e)
    {
        return e.length > 33 && (e = e.slice(0, 19) + "..." + e.slice(-13)),
        e;
    },
    _isAllowedExtension: function (e)
    {
        var t = -1 !== e.indexOf(".") ? e.replace(/.*[.]/, "").toLowerCase() : "",
            n = this._options.validation.allowedExtensions;
        if (!n.length)
        {
            return !0;
        }
        for (var i = 0; i < n.length; i++)
        {
            if (n[i].toLowerCase() == t)
            {
                return !0;
            }
        }
        return !1;
    },
    _formatSize: function (e)
    {
        var t = -1;
        do
        {
            e /= 1024,
            t++;
        } while (e > 99);
        return Math.max(e, .1).toFixed(1) + ["kB", "MB", "GB", "TB", "PB", "EB"][t];
    },
    _wrapCallbacks: function ()
    {
        var e, t;
        e = this,
        t = function (t, n, i)
        {
            try
            {
                return n.apply(e, i);
            }
            catch (o)
            {
                e.log("Caught exception in '" + t + "' callback - " + o, "error");
            }
        };
        for (var n in this._options.callbacks)
        {
            (function ()
            {
                var i = e._options.callbacks[n];
                e._options.callbacks[n] = function ()
                {
                    return t(n, i, arguments);
                };
            })();
        }
    },
    _parseFileName: function (e)
    {
        var t;
        return t = e.value ? e.value.replace(/.*(\/|\\)/, "") : null !== e.fileName && void 0 !== e.fileName ? e.fileName : e.name;
    },
    _parseFileSize: function (e)
    {
        var t;
        return e.value || (t = null !== e.fileSize && void 0 !== e.fileSize ? e.fileSize : e.size),
        t;
    },
    _getValidationDescriptor: function (e)
    {
        var t, n, i;
        return i = {},
        t = this._parseFileName(e),
        n = this._parseFileSize(e),
        i.name = t,
        n && (i.size = n),
        i;
    },
    _getValidationDescriptors: function (e)
    {
        var t, n;
        for (n = [], t = 0; t < e.length; t++)
        {
            n.push(e[t]);
        }
        return n;
    }
},
qq.FineUploader = function (e)
{
    qq.FineUploaderBasic.apply(this, arguments),
    qq.extend(this._options, {
        element: null,
        listElement: null,
        dragAndDrop: {
            extraDropzones: [],
            hideDropzones: !0,
            disableDefaultDropzone: !1
        },
        text: {
            uploadButton: "Upload a file",
            cancelButton: "Cancel",
            retryButton: "Retry",
            failUpload: "Upload failed",
            dragZone: "Drop files here to upload",
            formatProgress: "{percent}% of {total_size}",
            waitingForResponse: "Processing..."
        },
        template: '<div class="qq-uploader">' + (this._options.dragAndDrop && this._options.dragAndDrop.disableDefaultDropzone ? "" : '<div class="qq-upload-drop-area"><span>{dragZoneText}</span></div>') + (this._options.button ? "" : '<div class="qq-upload-button"><div>{uploadButtonText}</div></div>') + (this._options.listElement ? "" : '<ul class="qq-upload-list"></ul>') + "</div>",
        fileTemplate: '<li><div class="qq-progress-bar"></div><span class="qq-upload-spinner"></span><span class="qq-upload-finished"></span><span class="qq-upload-file"></span><span class="qq-upload-size"></span><a class="qq-upload-cancel" href="#">{cancelButtonText}</a><a class="qq-upload-retry" href="#">{retryButtonText}</a><span class="qq-upload-status-text">{statusText}</span></li>',
        classes: {
            button: "qq-upload-button",
            drop: "qq-upload-drop-area",
            dropActive: "qq-upload-drop-area-active",
            dropDisabled: "qq-upload-drop-area-disabled",
            list: "qq-upload-list",
            progressBar: "qq-progress-bar",
            file: "qq-upload-file",
            spinner: "qq-upload-spinner",
            finished: "qq-upload-finished",
            retrying: "qq-upload-retrying",
            retryable: "qq-upload-retryable",
            size: "qq-upload-size",
            cancel: "qq-upload-cancel",
            retry: "qq-upload-retry",
            statusText: "qq-upload-status-text",
            success: "qq-upload-success",
            fail: "qq-upload-fail",
            successIcon: null,
            failIcon: null
        },
        failedUploadTextDisplay: {
            mode: "default",
            maxChars: 50,
            responseProperty: "error",
            enableTooltip: !0
        },
        messages: {
            tooManyFilesError: "You may only drop one file"
        },
        retry: {
            showAutoRetryNote: !0,
            autoRetryNote: "Retrying {retryNum}/{maxAuto}...",
            showButton: !1
        },
        showMessage: function (e)
        {
            alert(e);
        }
    },
        !0),
    qq.extend(this._options, e, !0),
    this._wrapCallbacks(),
    this._options.template = this._options.template.replace(/\{dragZoneText\}/g, this._options.text.dragZone),
    this._options.template = this._options.template.replace(/\{uploadButtonText\}/g, this._options.text.uploadButton),
    this._options.fileTemplate = this._options.fileTemplate.replace(/\{cancelButtonText\}/g, this._options.text.cancelButton),
    this._options.fileTemplate = this._options.fileTemplate.replace(/\{retryButtonText\}/g, this._options.text.retryButton),
    this._options.fileTemplate = this._options.fileTemplate.replace(/\{statusText\}/g, ""),
    this._element = this._options.element,
    this._element.innerHTML = this._options.template,
    this._listElement = this._options.listElement || this._find(this._element, "list"),
    this._classes = this._options.classes,
    this._button || (this._button = this._createUploadButton(this._find(this._element, "button"))),
    this._bindCancelAndRetryEvents(),
    this._setupDragDrop();
},
qq.extend(qq.FineUploader.prototype, qq.FineUploaderBasic.prototype),
qq.extend(qq.FineUploader.prototype, {
    clearStoredFiles: function ()
    {
        qq.FineUploaderBasic.prototype.clearStoredFiles.apply(this, arguments),
        this._listElement.innerHTML = "";
    },
    addExtraDropzone: function (e)
    {
        this._setupExtraDropzone(e);
    },
    removeExtraDropzone: function (e)
    {
        var t = this._options.dragAndDrop.extraDropzones;
        for (var n in t)
        {
            if (t[n] === e)
            {
                return this._options.dragAndDrop.extraDropzones.splice(n, 1);
            }
        }
    },
    getItemByFileId: function (e)
    {
        for (var t = this._listElement.firstChild; t;)
        {
            if (t.qqFileId == e)
            {
                return t;
            }
            t = t.nextSibling;
        }
    },
    reset: function ()
    {
        qq.FineUploaderBasic.prototype.reset.apply(this, arguments),
        this._element.innerHTML = this._options.template,
        this._listElement = this._options.listElement || this._find(this._element, "list"),
        this._options.button || (this._button = this._createUploadButton(this._find(this._element, "button"))),
        this._bindCancelAndRetryEvents(),
        this._setupDragDrop();
    },
    _leaving_document_out: function (e)
    {
        return (qq.chrome() || qq.safari() && qq.windows()) && 0 == e.clientX && 0 == e.clientY || qq.firefox() && !e.relatedTarget;
    },
    _storeFileForLater: function (e)
    {
        qq.FineUploaderBasic.prototype._storeFileForLater.apply(this, arguments);
        var t = this.getItemByFileId(e);
        qq(this._find(t, "spinner")).hide();
    },
    _find: function (e, t)
    {
        var n = qq(e).getByClass(this._options.classes[t])[0];
        if (!n)
        {
            throw Error("element not found " + t);
        }
        return n;
    },
    _setupExtraDropzone: function (e)
    {
        this._options.dragAndDrop.extraDropzones.push(e),
        this._setupDropzone(e);
    },
    _setupDropzone: function (e)
    {
        var t = this,
            n = new qq.UploadDropZone({
                element: e,
                onEnter: function (n)
                {
                    qq(e).addClass(t._classes.dropActive),
                    n.stopPropagation();
                },
                onLeave: function ()
                {
                },
                onLeaveNotDescendants: function ()
                {
                    qq(e).removeClass(t._classes.dropActive);
                },
                onDrop: function (n)
                {
                    t._options.dragAndDrop.hideDropzones && qq(e).hide(),
                    qq(e).removeClass(t._classes.dropActive),
                    n.dataTransfer.files.length > 1 && !t._options.multiple ? t._error("tooManyFilesError", "") : t._uploadFileList(n.dataTransfer.files);
                }
            });
        this.addDisposer(function ()
        {
            n.dispose();
        }),
        this._options.dragAndDrop.hideDropzones && qq(e).hide();
    },
    _setupDragDrop: function ()
    {
        var e, t;
        e = this,
        this._options.dragAndDrop.disableDefaultDropzone || (t = this._find(this._element, "drop"), this._options.dragAndDrop.extraDropzones.push(t));
        var n, i = this._options.dragAndDrop.extraDropzones;
        for (n = 0; n < i.length; n++)
        {
            this._setupDropzone(i[n]);
        }
        this._options.dragAndDrop.disableDefaultDropzone || qq.ie() && !qq.ie10() || this._attach(document, "dragenter",
            function ()
            {
                if (!qq(t).hasClass(e._classes.dropDisabled))
                {
                    for (t.style.display = "block", n = 0; n < i.length; n++)
                    {
                        i[n].style.display = "block";
                    }
                }
            }),
        this._attach(document, "dragleave",
            function (t)
            {
                if (e._options.dragAndDrop.hideDropzones && qq.FineUploader.prototype._leaving_document_out(t))
                {
                    for (n = 0; n < i.length; n++)
                    {
                        qq(i[n]).hide();
                    }
                }
            }),
        qq(document).attach("drop",
            function (t)
            {
                if (e._options.dragAndDrop.hideDropzones)
                {
                    for (n = 0; n < i.length; n++)
                    {
                        qq(i[n]).hide();
                    }
                }
                t.preventDefault();
            });
    },
    _onSubmit: function (e, t)
    {
        qq.FineUploaderBasic.prototype._onSubmit.apply(this, arguments),
        this._addToList(e, t);
    },
    _onProgress: function (e, t, n, i)
    {
        qq.FineUploaderBasic.prototype._onProgress.apply(this, arguments);
        var o, s, r, a, l, u;
        o = this.getItemByFileId(e),
        s = this._find(o, "progressBar"),
        a = Math.round(100 * (n / i)),
        n === i ? (l = this._find(o, "cancel"), qq(l).hide(), qq(s).hide(), qq(this._find(o, "statusText")).setText(this._options.text.waitingForResponse), r = this._formatSize(i)) : (r = this._formatProgress(n, i), qq(s).css({
            display: "block"
        })),
        qq(s).css({
            width: a + "%"
        }),
        u = this._find(o, "size"),
        qq(u).css({
            display: "inline"
        }),
        qq(u).setText(r);
    },
    _onComplete: function (e, t, n)
    {
        qq.FineUploaderBasic.prototype._onComplete.apply(this, arguments);
        var i = this.getItemByFileId(e);
        qq(this._find(i, "statusText")).clearText(),
        qq(i).removeClass(this._classes.retrying),
        qq(this._find(i, "progressBar")).hide(),
        (!this._options.disableCancelForFormUploads || qq.UploadHandlerXhr.isSupported()) && qq(this._find(i, "cancel")).hide(),
        qq(this._find(i, "spinner")).hide(),
        n.success ? (qq(i).addClass(this._classes.success), this._classes.successIcon && (this._find(i, "finished").style.display = "inline-block", qq(i).addClass(this._classes.successIcon))) : (qq(i).addClass(this._classes.fail), this._classes.failIcon && (this._find(i, "finished").style.display = "inline-block", qq(i).addClass(this._classes.failIcon)), this._options.retry.showButton && !this._preventRetries[e] && qq(i).addClass(this._classes.retryable), this._controlFailureTextDisplay(i, n));
    },
    _onUpload: function (e)
    {
        qq.FineUploaderBasic.prototype._onUpload.apply(this, arguments);
        var t = this.getItemByFileId(e);
        this._showSpinner(t);
    },
    _onBeforeAutoRetry: function (e)
    {
        var t, n, i, o, s, r;
        qq.FineUploaderBasic.prototype._onBeforeAutoRetry.apply(this, arguments),
        t = this.getItemByFileId(e),
        n = this._find(t, "progressBar"),
        this._showCancelLink(t),
        n.style.width = 0,
        qq(n).hide(),
        this._options.retry.showAutoRetryNote && (i = this._find(t, "statusText"), o = this._autoRetries[e] + 1, s = this._options.retry.maxAutoAttempts, r = this._options.retry.autoRetryNote.replace(/\{retryNum\}/g, o), r = r.replace(/\{maxAuto\}/g, s), qq(i).setText(r), 1 === o && qq(t).addClass(this._classes.retrying));
    },
    _onBeforeManualRetry: function (e)
    {
        if (qq.FineUploaderBasic.prototype._onBeforeManualRetry.apply(this, arguments))
        {
            var t = this.getItemByFileId(e);
            return this._find(t, "progressBar").style.width = 0,
            qq(t).removeClass(this._classes.fail),
            this._showSpinner(t),
            this._showCancelLink(t),
            !0;
        }
        return !1;
    },
    _addToList: function (e, t)
    {
        var n = qq.toElement(this._options.fileTemplate);
        if (this._options.disableCancelForFormUploads && !qq.UploadHandlerXhr.isSupported())
        {
            var i = this._find(n, "cancel");
            qq(i).remove();
        }
        n.qqFileId = e;
        var o = this._find(n, "file");
        qq(o).setText(this._formatFileName(t)),
        qq(this._find(n, "size")).hide(),
        this._options.multiple || this._clearList(),
        this._listElement.appendChild(n);
    },
    _clearList: function ()
    {
        this._listElement.innerHTML = "",
        this.clearStoredFiles();
    },
    _bindCancelAndRetryEvents: function ()
    {
        var e = this,
            t = this._listElement;
        this._attach(t, "click",
            function (t)
            {
                t = t || window.event;
                var n = t.target || t.srcElement;
                if (qq(n).hasClass(e._classes.cancel) || qq(n).hasClass(e._classes.retry))
                {
                    qq.preventDefault(t);
                    for (var i = n.parentNode; void 0 == i.qqFileId;)
                    {
                        i = n = n.parentNode;
                    }
                    qq(n).hasClass(e._classes.cancel) ? (e.cancel(i.qqFileId), qq(i).remove()) : (qq(i).removeClass(e._classes.retryable), e.retry(i.qqFileId));
                }
            });
    },
    _formatProgress: function (e, t)
    {
        function n(e, t)
        {
            i = i.replace(e, t);
        }
        var i = this._options.text.formatProgress;
        return n("{percent}", Math.round(100 * (e / t))),
        n("{total_size}", this._formatSize(t)),
        i;
    },
    _controlFailureTextDisplay: function (e, t)
    {
        var n, i, o, s, r;
        n = this._options.failedUploadTextDisplay.mode,
        i = this._options.failedUploadTextDisplay.maxChars,
        o = this._options.failedUploadTextDisplay.responseProperty,
        "custom" === n ? (s = t[o], s ? s.length > i && (r = s.substring(0, i) + "...") : (s = this._options.text.failUpload, this.log("'" + o + "' is not a valid property on the server response.", "warn")), qq(this._find(e, "statusText")).setText(r || s), this._options.failedUploadTextDisplay.enableTooltip && this._showTooltip(e, s)) : "default" === n ? qq(this._find(e, "statusText")).setText(this._options.text.failUpload) : "none" !== n && this.log("failedUploadTextDisplay.mode value of '" + n + "' is not valid", "warn");
    },
    _showTooltip: function (e, t)
    {
        e.title = t;
    },
    _showSpinner: function (e)
    {
        var t = this._find(e, "spinner");
        t.style.display = "inline-block";
    },
    _showCancelLink: function (e)
    {
        if (!this._options.disableCancelForFormUploads || qq.UploadHandlerXhr.isSupported())
        {
            var t = this._find(e, "cancel");
            t.style.display = "inline";
        }
    },
    _error: function ()
    {
        var e = qq.FineUploaderBasic.prototype._error.apply(this, arguments);
        this._options.showMessage(e);
    }
}),
qq.UploadDropZone = function (e)
{
    this._options = {
        element: null,
        onEnter: function ()
        {
        },
        onLeave: function ()
        {
        },
        onLeaveNotDescendants: function ()
        {
        },
        onDrop: function ()
        {
        }
    },
    qq.extend(this._options, e),
    qq.extend(this, qq.DisposeSupport),
    this._element = this._options.element,
    this._disableDropOutside(),
    this._attachEvents();
},
qq.UploadDropZone.prototype = {
    _dragover_should_be_canceled: function ()
    {
        return qq.safari() || qq.firefox() && qq.windows();
    },
    _disableDropOutside: function ()
    {
        qq.UploadDropZone.dropOutsideDisabled || (this._dragover_should_be_canceled ? qq(document).attach("dragover",
                function (e)
                {
                    e.preventDefault();
                }) : qq(document).attach("dragover",
                    function (e)
                    {
                        e.dataTransfer && (e.dataTransfer.dropEffect = "none", e.preventDefault());
                    }), qq.UploadDropZone.dropOutsideDisabled = !0);
    },
    _attachEvents: function ()
    {
        var e = this;
        e._attach(e._element, "dragover",
            function (t)
            {
                if (e._isValidFileDrag(t))
                {
                    var n = qq.ie() ? null : t.dataTransfer.effectAllowed;
                    t.dataTransfer.dropEffect = "move" == n || "linkMove" == n ? "move" : "copy",
                    t.stopPropagation(),
                    t.preventDefault();
                }
            }),
        e._attach(e._element, "dragenter",
            function (t)
            {
                e._isValidFileDrag(t) && e._options.onEnter(t);
            }),
        e._attach(e._element, "dragleave",
            function (t)
            {
                if (e._isValidFileDrag(t))
                {
                    e._options.onLeave(t);
                    var n = document.elementFromPoint(t.clientX, t.clientY);
                    qq(this).contains(n) || e._options.onLeaveNotDescendants(t);
                }
            }),
        e._attach(e._element, "drop",
            function (t)
            {
                e._isValidFileDrag(t) && (t.preventDefault(), e._options.onDrop(t));
            });
    },
    _isValidFileDrag: function (e)
    {
        if (qq.ie() && !qq.ie10())
        {
            return !1;
        }
        var t = e.dataTransfer,
            n = qq.safari(),
            i = qq.ie10() ? !0 : "none" != t.effectAllowed;
        return t && i && (t.files || !n && t.types.contains && t.types.contains("Files"));
    }
},
qq.UploadHandlerAbstract = function (e)
{
    this._options = {
        debug: !1,
        endpoint: "/upload.php",
        maxConnections: 999,
        log: function ()
        {
        },
        onProgress: function ()
        {
        },
        onComplete: function ()
        {
        },
        onCancel: function ()
        {
        },
        onUpload: function ()
        {
        },
        onAutoRetry: function ()
        {
        }
    },
    qq.extend(this._options, e),
    this._queue = [],
    this._params = [],
    this.log = this._options.log;
},
qq.UploadHandlerAbstract.prototype = {
    add: function ()
    {
    },
    upload: function (e, t)
    {
        var n = this._queue.push(e),
            i = {};
        qq.extend(i, t),
        this._params[e] = i,
        n <= this._options.maxConnections && this._upload(e, this._params[e]);
    },
    retry: function (e)
    {
        var t = qq.indexOf(this._queue, e);
        t >= 0 ? this._upload(e, this._params[e]) : this.upload(e, this._params[e]);
    },
    cancel: function (e)
    {
        this.log("Cancelling " + e),
        this._cancel(e),
        this._dequeue(e);
    },
    cancelAll: function ()
    {
        for (var e = 0; e < this._queue.length; e++)
        {
            this._cancel(this._queue[e]);
        }
        this._queue = [];
    },
    getName: function ()
    {
    },
    getSize: function ()
    {
    },
    getQueue: function ()
    {
        return this._queue;
    },
    reset: function ()
    {
        this.log("Resetting upload handler"),
        this._queue = [],
        this._params = [];
    },
    _upload: function ()
    {
    },
    _cancel: function ()
    {
    },
    _dequeue: function (e)
    {
        var t = qq.indexOf(this._queue, e);
        this._queue.splice(t, 1);
        var n = this._options.maxConnections;
        if (this._queue.length >= n && t < n)
        {
            var i = this._queue[n - 1];
            this._upload(i, this._params[i]);
        }
    },
    isValid: function ()
    {
    }
},
qq.UploadHandlerForm = function ()
{
    qq.UploadHandlerAbstract.apply(this, arguments),
    this._inputs = {},
    this._detach_load_events = {};
},
qq.extend(qq.UploadHandlerForm.prototype, qq.UploadHandlerAbstract.prototype),
qq.extend(qq.UploadHandlerForm.prototype, {
    add: function (e)
    {
        e.setAttribute("name", this._options.inputName);
        var t = "qq-upload-handler-iframe" + qq.getUniqueId();
        return this._inputs[t] = e,
        e.parentNode && qq(e).remove(),
        t;
    },
    getName: function (e)
    {
        return this._inputs[e].value.replace(/.*(\/|\\)/, "");
    },
    isValid: function (e)
    {
        return void 0 !== this._inputs[e];
    },
    reset: function ()
    {
        qq.UploadHandlerAbstract.prototype.reset.apply(this, arguments),
        this._inputs = {},
        this._detach_load_events = {};
    },
    _cancel: function (e)
    {
        this._options.onCancel(e, this.getName(e)),
        delete this._inputs[e],
        delete this._detach_load_events[e];
        var t = document.getElementById(e);
        t && (t.setAttribute("src", "javascript:false;"), qq(t).remove());
    },
    _upload: function (e, t)
    {
        this._options.onUpload(e, this.getName(e), !1);
        var n = this._inputs[e];
        if (!n)
        {
            throw Error("file with passed id was not added, or already uploaded or cancelled");
        }
        var i = this.getName(e);
        t[this._options.inputName] = i;
        var o = this._createIframe(e),
            s = this._createForm(o, t);
        s.appendChild(n);
        var r = this;
        return this._attachLoadEvent(o,
            function ()
            {
                r.log("iframe loaded");
                var t = r._getIframeContentJSON(o);
                setTimeout(function ()
                {
                    r._detach_load_events[e](),
                    delete r._detach_load_events[e],
                    qq(o).remove();
                },
                    1),
                (t.success || !r._options.onAutoRetry(e, i, t)) && (r._options.onComplete(e, i, t), r._dequeue(e));
            }),
        this.log("Sending upload request for " + e),
        s.submit(),
        qq(s).remove(),
        e;
    },
    _attachLoadEvent: function (e, t)
    {
        var n = this;
        this._detach_load_events[e.id] = qq(e).attach("load",
            function ()
            {
                if (n.log("Received response for " + e.id), e.parentNode)
                {
                    try
                    {
                        if (e.contentDocument && e.contentDocument.body && "false" == e.contentDocument.body.innerHTML)
                        {
                            return;
                        }
                    }
                    catch (i)
                    {
                        n.log("Error when attempting to access iframe during handling of upload response (" + i + ")", "error");
                    }
                    t();
                }
            });
    },
    _getIframeContentJSON: function (iframe)
    {
        try
        {
            var doc = iframe.contentDocument ? iframe.contentDocument : iframe.contentWindow.document,
                response,
                innerHTML = doc.body.innerHTML;
            this.log("converting iframe's innerHTML to JSON"),
            this.log("innerHTML = " + innerHTML),
            innerHTML && innerHTML.match(/^<pre/i) && (innerHTML = doc.body.firstChild.firstChild.nodeValue),
            response = eval("(" + innerHTML + ")");
        }
        catch (error)
        {
            this.log("Error when attempting to parse form upload response (" + error + ")", "error"),
            response = {
                success: !1
            };
        }
        return response;
    },
    _createIframe: function (e)
    {
        var t = qq.toElement('<iframe src="javascript:false;" name="' + e + '" />');
        return t.setAttribute("id", e),
        t.style.display = "none",
        document.body.appendChild(t),
        t;
    },
    _createForm: function (e, t)
    {
        var n = this._options.demoMode ? "GET" : "POST",
            i = qq.toElement('<form method="' + n + '" enctype="multipart/form-data"></form>'),
            o = qq.obj2url(t, this._options.endpoint);
        return i.setAttribute("action", o),
        i.setAttribute("target", e.name),
        i.style.display = "none",
        document.body.appendChild(i),
        i;
    }
}),
qq.UploadHandlerXhr = function ()
{
    qq.UploadHandlerAbstract.apply(this, arguments),
    this._files = [],
    this._xhrs = [],
    this._loaded = [];
},
qq.UploadHandlerXhr.isSupported = function ()
{
    var e = document.createElement("input");
    return e.type = "file",
    "multiple" in e && "undefined" != typeof File && "undefined" != typeof FormData && "undefined" != typeof (new XMLHttpRequest).upload;
},
qq.extend(qq.UploadHandlerXhr.prototype, qq.UploadHandlerAbstract.prototype),
qq.extend(qq.UploadHandlerXhr.prototype, {
    add: function (e)
    {
        if (!(e instanceof File))
        {
            throw Error("Passed obj in not a File (in qq.UploadHandlerXhr)");
        }
        return this._files.push(e) - 1;
    },
    getName: function (e)
    {
        var t = this._files[e];
        return null !== t.fileName && void 0 !== t.fileName ? t.fileName : t.name;
    },
    getSize: function (e)
    {
        var t = this._files[e];
        return null != t.fileSize ? t.fileSize : t.size;
    },
    getLoaded: function (e)
    {
        return this._loaded[e] || 0;
    },
    isValid: function (e)
    {
        return void 0 !== this._files[e];
    },
    reset: function ()
    {
        qq.UploadHandlerAbstract.prototype.reset.apply(this, arguments),
        this._files = [],
        this._xhrs = [],
        this._loaded = [];
    },
    _upload: function (e, t)
    {
        this._options.onUpload(e, this.getName(e), !0);
        var n = this._files[e],
            i = this.getName(e);
        this.getSize(e),
        this._loaded[e] = 0;
        var o = this._xhrs[e] = new XMLHttpRequest,
            s = this;
        o.upload.onprogress = function (t)
        {
            t.lengthComputable && (s._loaded[e] = t.loaded, s._options.onProgress(e, i, t.loaded, t.total));
        },
        o.onreadystatechange = function ()
        {
            4 == o.readyState && s._onComplete(e, o);
        },
        t = t || {},
        t[this._options.inputName] = i;
        var r = qq.obj2url(t, this._options.endpoint),
            a = this._options.demoMode ? "GET" : "POST";
        if (o.open(a, r, !0), o.setRequestHeader("X-Requested-With", "XMLHttpRequest"), o.setRequestHeader("X-File-Name", encodeURIComponent(i)), o.setRequestHeader("Cache-Control", "no-cache"), this._options.forceMultipart)
        {
            var l = new FormData;
            l.append(this._options.inputName, n),
            n = l;
        }
        else
        {
            o.setRequestHeader("Content-Type", "application/octet-stream"),
            o.setRequestHeader("X-Mime-Type", n.type);
        }
        for (key in this._options.customHeaders)
        {
            o.setRequestHeader(key, this._options.customHeaders[key]);
        }
        this.log("Sending upload request for " + e),
        o.send(n);
    },
    _onComplete: function (id, xhr)
    {
        "use strict";
        if (this._files[id])
        {
            var name = this.getName(id),
                size = this.getSize(id),
                response;
            this._options.onProgress(id, name, size, size),
            this.log("xhr - server response received for " + id),
            this.log("responseText = " + xhr.responseText);
            try
            {
                response = "function" === typeof JSON.parse ? JSON.parse(xhr.responseText) : eval("(" + xhr.responseText + ")");
            }
            catch (error)
            {
                this.log("Error when attempting to parse xhr response text (" + error + ")", "error"),
                response = {};
            }
            (200 === xhr.status && response.success || !this._options.onAutoRetry(id, name, response, xhr)) && (this._options.onComplete(id, name, response, xhr), this._xhrs[id] = null, this._dequeue(id));
        }
    },
    _cancel: function (e)
    {
        this._options.onCancel(e, this.getName(e)),
        this._files[e] = null,
        this._xhrs[e] && (this._xhrs[e].abort(), this._xhrs[e] = null);
    }
});